#include <iostream>
#include <string>
#include <functional>

#include <sys/types.h> //socket网络文件创建
#include <sys/socket.h>
#include <arpa/inet.h> //htonl()
#include <netinet/in.h> //sockaddr

#include <cerrno> //错误码
#include <cstring> //错误码描述

#include <strings.h> //void bzero()

#include "err.hpp" //错误码归纳
#include "mythread.hpp" //错误码归纳

namespace my_client
{
    class Client
    {
    public:
        Client(std::string ip,uint16_t port)
            :_ip(ip) //连接的服务器IP
            ,_port(port) //连接的服务器端口
            ,_sock(0) //本地套接字文件描述符
            ,_c(nullptr)
            ,_p(nullptr)
        {
            _p = new Thread("_p",std::bind(&Client::Send,this));
            _c = new Thread("_c",std::bind(&Client::Reception,this));
        }

        // void InitClient()
        // {
        //     _sock = socket(AF_INET,SOCK_DGRAM,0);
        //     if(_sock < 0)
        //     {
        //         std::cout<<"create socket error: "<< strerror(errno) << std::endl;
        //         exit(SOCK_ERR);
        //     }
        //     //std::cout<<"socket:"<<_sock<<std::endl; //正常情况下是3
        // }

        // void Start()
        // {
        //     struct sockaddr_in local;
        //     bzero(&local,sizeof(local));
        //     local.sin_family = AF_INET;
        //     local.sin_port = htons(_port);
        //     local.sin_addr.s_addr = inet_addr(_ip.c_str()); ///ip已经处理过了

        //     while(true)
        //     {
        //         std::string str;
        //         //std::cin>>str;
        //         std::cout<<"[client-668]# ";
        //         std::getline(std::cin,str);
        //         int ret = sendto(_sock,str.c_str(),str.size(),0,(struct sockaddr*)(&local),sizeof(local)); //向服务器发送数据
        //         if(ret == -1)
        //         {
        //             std::cout<<"sendto error:"<<strerror(errno)<<std::endl;
        //             exit(SENDTO_ERR);
        //         }
        //         const int size = 1024;
        //         char buf[size] = {0};
        //         socklen_t locallen = (unsigned int)sizeof(local);
        //         ret = recvfrom(_sock,buf,size-1,0,(struct sockaddr*)(&local),&locallen); //接收服务器的响应
        //         if(ret == -1)
        //         {
        //             std::cout<<"recvfrom error:"<<strerror(errno)<<std::endl;
        //             exit(REVCFROM_ERR);
        //         }
        //         buf[size-1] = '\0';
        //         std::cout<<"服务器:\n"<<buf<<std::endl;

        //     }

        void Start()
        {
            _sock = socket(AF_INET,SOCK_DGRAM,0);
            if(_sock < 0)
            {
                std::cout<<"create socket error: "<< strerror(errno) << std::endl;
                exit(SOCK_ERR);
            }
            //std::cout<<"socket:"<<_sock<<std::endl; //正常情况下是3

            //不需要自己手动bind 第一次调用sendto操作系统会自己bind

            _p->run();
            _c->run();
        }

        void Send()
        {
            struct sockaddr_in local;
            bzero(&local,sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            local.sin_addr.s_addr = inet_addr(_ip.c_str()); ///ip已经处理过了.

            std::string str;
            while(true)
            {
                std::cerr<<"[client-668]# ";
                std::getline(std::cin,str);
                sendto(_sock,str.c_str(),str.size(),0,(struct sockaddr*)(&local),sizeof(local)); //向服务器发送数据
            }

        }

        void Reception()
        {
            while(true)
            {
                struct sockaddr_in local;
                const int size = 2048;
                char buf[size] = {0};
                socklen_t locallen = (unsigned int)sizeof(local);
                int ret = recvfrom(_sock,buf,size-1,0,(struct sockaddr*)(&local),&locallen); //接收服务器的响应
                if(ret > 0)
                {
                    buf[size-1] = '\0';
                    std::cout<<buf<<std::endl;
                }
            }
        }

        ~Client()
        {
            _p->join();
            _c->join();

            delete _p;
            delete _c;
        }

    private:
        std::string _ip;
        uint16_t _port;
        int _sock;

        Thread* _p;
        Thread* _c;
    };
}